﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ColorClusteringSOM.Visualation;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace ColorClusteringSOM
{
    public partial class Visualization : Form
    {
        private Network visualizedNetwork = null;

        private int rows = -1;
        private int cols = -1;

        //startovaci pozice na platne, NEMENI SE!!
        const int startX = 40;
        const int startY = 20;

        private SolidBrush[,] brushMatrix = null;

        //velikost ctverce default je 1px
        //Meni se podle poctu neuronu
        private int sizeOfSquare = -1;

        //vyherci po clasifikaci (zatim bez clusterizace)
        private Neuron[] winners = null;

        //Leadri clusterizace
        private List<NeuronRough> leaders = null;

        VisHelper visHelper = null;
        String fileName = String.Empty;

        private String nameBMPfile = String.Empty;

        #region Properties
        public Network VisualizedNetwork { get { return this.visualizedNetwork; } set { this.visualizedNetwork = value; } }
        public SolidBrush[,] BrushMatrix { get { return this.brushMatrix; } }

        public int Rows { get { return this.rows; } set { this.rows = value; } }

        public int Cols { get { return this.cols; } set { this.cols = value; } }

        public int SizeOfSquare { get { return this.sizeOfSquare; } set { this.sizeOfSquare = value; } }

        public int CoordinaX(int number)
        {
            return (startX + (number * sizeOfSquare));

        }
        public int CoordinaY(int number)
        {
            return (startY + (number * sizeOfSquare));

        }

        #endregion



        public Visualization(Network network,String fileName)
        {
            this.fileName = fileName;
            int heightWeight = 700;
            InitializeComponent();
            this.Width = heightWeight;
            this.Height = heightWeight;
            this.VisualizedNetwork = network;
            this.Rows = network.Rows;
            this.Cols = network.Cols;
            this.SizeOfSquare = ((heightWeight - 60) / Rows);
            this.brushMatrix = new SolidBrush[this.rows, this.cols];
            TransferSOM();
            visHelper = new VisHelper();
            

        }

        /// <summary>
        /// Konstruktor pro zobrazeni vysledku klasifikace
        /// zobrazi tedy SOM a viteze
        /// </summary>
        /// <param name="network">SOM</param>
        /// <param name="winners">pole vitezu</param>
        public Visualization(Network network,String fileName, Neuron[] winners)
            : this(network,fileName)
        {

            this.winners = winners;

            MarkingWinners();
            TransferMatrixForPainting();
            labelInfo.Text = "Neurons=" + (Rows * Cols) + ", sizeOfSquare=" + SizeOfSquare;


        }

        /// <summary>
        /// Konstruktor pro zobrazeni clustru tzn leaderu a jejich 
        /// hornich a dolnich aproximaci
        /// </summary>
        /// <param name="network">SOM</param>
        /// <param name="leaders">Leaders</param>
        public Visualization(Network network, List<NeuronRough> leaders,String fileName,String info)
            : this(network,fileName)
        {
            this.leaders = leaders;
            labelInfo.Text = info;
        }



        protected void PaintLeaders(PaintEventArgs paintEvnt)
        {
            Graphics gfx = paintEvnt.Graphics;

            foreach (NeuronRough neuron in leaders)
            {

                SolidBrush brush = new SolidBrush(Color.Black);
                int Xcor = (startX + (neuron.X * sizeOfSquare));
                int Ycor = (startY + (neuron.Y * sizeOfSquare));
                Console.WriteLine("Neuron X={0} Y={1}, Xcor={2} Ycor={3}", neuron.X, neuron.Y, Xcor, Ycor);
                gfx.FillRectangle(brush, Xcor, Ycor, sizeOfSquare, sizeOfSquare);
            }
        }


        /// <summary>
        /// Metoda, ktera jenom prevede sit Network na 
        /// dvourozmerne pole SolidBrush. tzn prevod RGB
        /// 
        /// a neurony, ktere jsou oznaceny jako vitezove, bude jim zmenena barva
        ///  </summary>
        protected void TransferMatrixForPainting()
        {
            Neuron neuron = null;
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    neuron = visualizedNetwork[i, j];

                    if (!neuron.Winner)
                        brushMatrix[i, j] = new SolidBrush(neuron.RGBColor);
                    else
                    {
                        brushMatrix[i, j] = new SolidBrush(Color.Black);

                    }
                }
            }
        }

        /// <summary>
        /// Metoda, ktera jenom prevede sit Network na 
        /// dvourozmerne pole SolidBrush. tzn prevod RGB
        ///  </summary>
        protected void TransferSOM()
        {
            Neuron neuron = null;
            for (int i = 0; i < Rows; i++)
            {
                for (int j = 0; j < Cols; j++)
                {
                    neuron = visualizedNetwork[i, j];

                    brushMatrix[i, j] = new SolidBrush(neuron.RGBColor);

                }
            }
        }


        /// <summary>
        /// Kresleni neuronove site
        /// </summary>
        /// <param name="paintEvnt"></param>
        protected override void OnPaint(PaintEventArgs paintEvnt)
        {
            //Console.WriteLine("Painting...");

            Graphics gfx = paintEvnt.Graphics;
            

            //Pen myPen = new Pen(Color.Black);

            //Pozice pro pruchod polem
            int i = 0;
            int j = 0;

            ////startovaci pozice na platne, NEMENI SE!!
            //int startX = 40;
            //int startY = 20;

            //cilove pozice na platne, meni se podle velikosti ctverce a poctu neuronu
            //TODO: Nekdy nevykresli posledni sloupec somu pri heightwidth=600 a pri siti 15x15
            int endX = this.SizeOfSquare * Rows;
            int endY = this.SizeOfSquare * Cols;

            //Krok pohybu na platne = velikost ctverce !!!
            for (int x = startX; x <= endX; x = x + sizeOfSquare)
            {
                for (int y = startY; y <= endX; y = y + sizeOfSquare)
                {

                    gfx.FillRectangle(brushMatrix[i, j], x, y, sizeOfSquare, sizeOfSquare);

                    {

                    }
                    //gfx.DrawRectangle(myPen, i, j, 20, 20);
                    j++;
                }
                i++;
                j = 0;
            }
            



            Pen pen = null;
            int counter = 0;
            if (leaders == null)
            {
                FormPrint(this);
                return;
            }
            foreach (NeuronRough neuron in leaders)
            {
                counter++;
                pen = new Pen(Color.Black);
                pen.Width = 3;
                Brush b = new SolidBrush(Color.Black);
                Font myFont = new Font("Arial", 15, FontStyle.Bold);

                int Xleader = (startX + (neuron.X * sizeOfSquare));
                int Yleader = (startY + (neuron.Y * sizeOfSquare));

                

                // visHelper.ListToArray(neuron.LowerAppNeuronsArray);

                int Xcor = 0;
                int Ycor = 0;
                //LOWER APPROXIMATION
                foreach (NeuronRough nLow in neuron.LowerAppNeuronsArray)
                {
                    pen = new Pen(Color.DarkBlue);
                    //pen.DashCap = System.Drawing.Drawing2D.DashCap.Round;
                    pen.Width = 1;

                    Xcor = CoordinaX(nLow.X);
                    Ycor = CoordinaY(nLow.Y);

                    //gfx.DrawRectangle(pen, Xcor, Ycor, sizeOfSquare, sizeOfSquare);
                    HatchBrush myHatchBrush = new HatchBrush(HatchStyle.DiagonalBrick, Color.Black, nLow.Neuron.RGBColor);
                    gfx.FillRectangle(myHatchBrush, Xcor, Ycor, sizeOfSquare, sizeOfSquare);
                    //gfx.DrawLine(pen, Xleader + (sizeOfSquare / 2), Yleader + (sizeOfSquare / 2), Xcor + (sizeOfSquare / 2), Ycor + (sizeOfSquare / 2));
                }

                //UPPER APROXIMATION
                foreach (Neuron nUp in neuron.UpperAppNeuronsArray)
                {
                    pen = new Pen(Color.Red);
                    pen.Width = 1;

                    Xcor = CoordinaX(nUp.X);
                    Ycor = CoordinaY(nUp.Y);

                    //gfx.DrawRectangle(pen, Xcor, Ycor, sizeOfSquare, sizeOfSquare);
                    gfx.DrawLine(pen, Xleader + (sizeOfSquare / 2), Yleader + (sizeOfSquare / 2), Xcor + (sizeOfSquare / 2), Ycor + (sizeOfSquare / 2));
                }
                pen = new Pen(Color.Black);
                pen.Width = 3;
                gfx.DrawRectangle(pen, Xleader, Yleader, sizeOfSquare, sizeOfSquare);
               
                gfx.DrawString("C" + counter, myFont, b, Xleader + (sizeOfSquare / 2), Yleader + (sizeOfSquare / 2));
            }

            FormPrint(this);
           
        }

        private void FormPrint(Control c)
        {

            VisHelper.SaveAsBitmap(this, fileName+".bmp");
            

        }

        /// <summary>
        /// Metoda, ktera oznaci viteze 
        /// TODO: tuto metodu a celou pripravu dat pro vizualizaci by mela delat jinaci trida
        /// </summary>
        protected void MarkingWinners()
        {
            Neuron neuron = null;

            for (int i = 0; i < winners.Length; i++)
            {
                neuron = winners[i];

                visualizedNetwork[neuron.X, neuron.Y].Winner = true;


            }

        }


    }
}
